package cn.mumzone.basic.base;

import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;


import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Stack;

import butterknife.ButterKnife;
import butterknife.Unbinder;
import cn.mumzone.basic.R;
import cn.mumzone.basic.loading.dialog.LoadingDialog;
import cn.mumzone.basic.loading.dialog.VaryViewHelperController;
import cn.mumzone.basic.mvp.BasePresenter;
import cn.mumzone.basic.mvp.BaseView;
import cn.mumzone.basic.netstatus.NetUtils;
import cn.mumzone.basic.util.IsFastClickUtil;
import cn.mumzone.basic.util.PosToast;
import cn.mumzone.basic.util.ToastUtil;


/**
 * Author Chaney
 * Date   2017/3/7 上午10:24.
 * EMail  qiuzhenhuan.hi@gmail.com
 */

public abstract class BaseFragment<T extends BasePresenter> extends Fragment implements BaseView {

    protected int mScreenWidth = 0;
    protected int mScreenHeight = 0;
    protected float mScreenDensity = 0.0f;

    private boolean isFirstResume = true;
    private boolean isFirstVisible = true;
    private boolean isFirstInvisible = true;
    private boolean isPrepared;

    protected T mPresenter;
    protected Activity mActivity;
    protected Context mContext;
    protected View mView;
    private Stack<LoadingDialog> mDialogStack = new Stack<>();


    // 替换布局
    private VaryViewHelperController mVaryViewHelperController = null;
    private Unbinder unbinder;
    protected MyHandler mHandler = new MyHandler(this);

    @Override
    public void onAttach(Context context) {
        this.mActivity = (Activity) context;
        this.mContext = context;
        super.onAttach(context);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
                             @Nullable Bundle savedInstanceState) {
        if (getLayout() != 0) {
            mView = inflater.inflate(getLayout(), null);
            initVariable();
            if (!hasViewPermission()) {
                FrameLayout frameLayout = new FrameLayout(mContext);
                frameLayout.addView(mView);
                View permissionView = inflater.inflate(R.layout.view_permission, null);
                frameLayout.addView(permissionView);
                mView.setVisibility(View.GONE);
                permissionView.setVisibility(View.VISIBLE);
                mView = frameLayout;
            }
            return mView;
        } else {
            return super.onCreateView(inflater, container, savedInstanceState);
        }
    }

    protected boolean hasViewPermission() {
        return true;
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        unbinder = ButterKnife.bind(this, mView);

        if (hasViewPermission()) {

            if (null != getTargetView()) {
                mVaryViewHelperController = new VaryViewHelperController(getTargetView());
            }

            if (null != getArguments()) {
                getBundleExtras(getArguments());
            }

            initScreenData();

            initPresenter();

            initEventAndData();

            if (!NetUtils.isNetworkAvailable(mContext)) {
                if (null != getTargetView()) {
                    showNetErrorEmpty(new View.OnClickListener() {
                        @Override
                        public void onClick(View v) {
                            if (!NetUtils.isNetworkConnected(mContext)) {
                                PosToast.INSTANCE.makeShortToast(mContext, "网络不给力，请稍后再试");
                                return;
                            }
                            if (getTargetView() != null) toggleCloseEmpty();
                            refreshNetwork();
                        }
                    });
                }
            }
        }

    }

    /**
     * 获取屏幕宽高信息
     */
    private void initScreenData() {
        DisplayMetrics displayMetrics = new DisplayMetrics();
        getActivity().getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
        mScreenDensity = displayMetrics.density;
        mScreenHeight = displayMetrics.heightPixels;
        mScreenWidth = displayMetrics.widthPixels;
    }

    /**
     * 获取 Presenter 泛型实例
     */
    private void initPresenter() {
        Type type = getClass().getGenericSuperclass();
        if (type instanceof ParameterizedType) {
            Type[] types = ((ParameterizedType) type).getActualTypeArguments();
            Class<T> presenterClass = (Class<T>) types[0];
            try {
                mPresenter = presenterClass.newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (mPresenter != null) {
            mPresenter.attachView(this);
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        if (unbinder != Unbinder.EMPTY) {
            unbinder.unbind();
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        if (mPresenter != null) {
            mPresenter.detachView();
        }
        closeAllLoadingDialog();
    }

    private void closeAllLoadingDialog() {
        if (!mDialogStack.isEmpty()) {
            while (!mDialogStack.isEmpty()) {
                LoadingDialog dialog = mDialogStack.pop();
                dialog.dismiss();
            }
        }
    }

    @Override
    public void showLoadingDialog() {
        LoadingDialog dialog = new LoadingDialog.Builder(mContext)
                .setMessage("正在加载中...")
                .setCancelable(false)
                .create();
        dialog.show();
        mDialogStack.push(dialog);
    }

    @Override
    public void dismissLoadingDialog() {
        if (!mDialogStack.isEmpty()) {
            LoadingDialog dialog = mDialogStack.pop();
            dialog.dismiss();
        }
    }

    @Override
    public void onDetach() {
        super.onDetach();
        // java.lang.IllegalStateException: Activity has been destroyed
        try {
            Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
            childFragmentManager.setAccessible(true);
            childFragmentManager.set(this, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        if (hasViewPermission()) {
            initPrepare();
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        if (hasViewPermission()) {
            if (isFirstResume) {
                isFirstResume = false;
                return;
            }
            if (getUserVisibleHint() && !isHidden() && hasViewPermission()) {
                onUserVisible();
            }
        }
    }

    @Override
    public void onHiddenChanged(boolean hidden) {
        super.onHiddenChanged(hidden);
        if (hasViewPermission()) {
            if (!isHidden()) {
                onUserVisible();
            }
        }
    }

    @Override
    public void onPause() {
        super.onPause();
        if (hasViewPermission()) {
            if (getUserVisibleHint() && !isHidden()) {
                onUserInvisible();
            }
        }
    }

    @Override
    public void setUserVisibleHint(boolean isVisibleToUser) {
        super.setUserVisibleHint(isVisibleToUser);

        if (hasViewPermission()) {
            if (isVisibleToUser) {
                if (isFirstVisible) {
                    isFirstVisible = false;
                    initPrepare();
                } else {
                    onUserVisible();
                }
            } else {
                if (isFirstInvisible) {
                    isFirstInvisible = false;
                    onFirstUserInvisible();
                } else {
                    onUserInvisible();
                }
            }
        }
    }

    private synchronized void initPrepare() {
        if (isPrepared) {
            onFirstUserVisible();
        } else {
            isPrepared = true;
        }
    }

    /**
     * when fragment is visible for the first time, here we can do some initialized work or refresh data only once
     */
    protected void onFirstUserVisible() {

    }


    protected abstract void onUserVisible();

    /**
     * when fragment is invisible for the first time
     */
    private void onFirstUserInvisible() {
        // here we do not recommend do something
    }

    /**
     * this method like the fragment's lifecycle method onPause()
     */
    protected void onUserInvisible() {

    }

    /**
     * startActivity
     *
     * @param clazz
     */
    protected void readyGo(Class<?> clazz) {
        Intent intent = new Intent(getActivity(), clazz);
        startActivity(intent);
    }

    /**
     * startActivity with bundle
     *
     * @param clazz
     * @param bundle
     */
    protected void readyGo(Class<?> clazz, Bundle bundle) {
        Intent intent = new Intent(getActivity(), clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivity(intent);
    }

    /**
     * startActivityForResult
     *
     * @param clazz
     * @param requestCode
     */
    protected void readyGoForResult(Class<?> clazz, int requestCode) {
        Intent intent = new Intent(getActivity(), clazz);
        startActivityForResult(intent, requestCode);
    }

    /**
     * startActivityForResult with bundle
     *
     * @param clazz
     * @param requestCode
     * @param bundle
     */
    protected void readyGoForResult(Class<?> clazz, int requestCode, Bundle bundle) {
        Intent intent = new Intent(getActivity(), clazz);
        if (null != bundle) {
            intent.putExtras(bundle);
        }
        startActivityForResult(intent, requestCode);
    }

    protected void toggleShowEmpty(boolean toggle, int img, String msg, String emptyGoText, View.OnClickListener onClickListener) {
        if (null == mVaryViewHelperController) {
            throw new IllegalArgumentException("You must return a right target view for loading");
        }

        if (toggle) {
            mVaryViewHelperController.showEmpty(img, msg, emptyGoText, onClickListener);
        } else {
            mVaryViewHelperController.restore();
        }
    }

    protected void toggleShowEmpty(boolean toggle, int img, String msg, String secondeMsg) {
        if (null == mVaryViewHelperController) {
            throw new IllegalArgumentException("You must return a right target view for loading");
        }

        if (toggle) {
            mVaryViewHelperController.showEmpty(img, msg, secondeMsg);
        } else {
            mVaryViewHelperController.restore();
        }
    }

    protected void toggleShowEmpty(boolean toggle) {
        this.toggleShowEmpty(toggle, -1, "", "", null);
    }

    protected void toggleCloseEmpty() {
        if (null == mVaryViewHelperController) {
            throw new IllegalArgumentException("You must return a right target view for loading");
        }
        mVaryViewHelperController.restore();
    }

    protected void showNetErrorEmpty() {
        if (null == mVaryViewHelperController) {
            throw new IllegalArgumentException("You must return a right target view for loading");
        }

        mVaryViewHelperController.showNetError(false, null);
    }

    protected void showNetErrorEmpty(View.OnClickListener onClickListener) {
        if (null == mVaryViewHelperController) {
            throw new IllegalArgumentException("You must return a right target view for loading");
        }
        mVaryViewHelperController.showNetError(true, onClickListener);
    }

    protected void closeDialog(Dialog... dialogArray) {
        for (Dialog dialog : dialogArray) {
            if (dialog != null && dialog.isShowing()) {
                dialog.dismiss();
            }
        }
    }

    protected void showDialog(Dialog dialog) {
        if (dialog != null && !dialog.isShowing()) {
            dialog.show();
        }
    }

    /**
     * 使用软引用的 Handler
     * 避免不当操作导致的内存泄漏
     */
    public static class MyHandler extends Handler {
        private WeakReference<BaseFragment> mActivity;

        public MyHandler(BaseFragment fragment) {
            mActivity = new WeakReference<>(fragment);
        }

        @Override
        public void handleMessage(Message msg) {
            if (mActivity.get() != null) {
                mActivity.get().handleMsg(msg);
            }
        }
    }

    public void showError(String msg) {
        PosToast.INSTANCE.makeShortToast(mContext, msg + "~");
    }

    @Override
    public void showNetError() {
        if (null != getTargetView()) {
            showNetErrorEmpty(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    if (!NetUtils.isNetworkConnected(mContext)) {
                        PosToast.INSTANCE.makeShortToast(mContext, "网络不给力，请稍后再试");
                        return;
                    }
                    if (getTargetView() != null) toggleCloseEmpty();
                    refreshNetwork();
                }
            });
        }
    }

    protected void handleMsg(Message msg) {
    }


    protected void getBundleExtras(Bundle extras) {
    }


    protected View getTargetView() {
        return null;
    }

    protected void initVariable() {
    }

    protected void refreshNetwork() {
    }

    protected abstract void initEventAndData();

    protected abstract int getLayout();

    public void setViewVisibility(View view, boolean v_or_gone) {
        if (view == null) {
            ToastUtil.debugToast(mContext, "You must keep the view not null", false);
            return;
        }
        view.setVisibility(v_or_gone ? View.VISIBLE : View.GONE);
    }

    public void setViewVisibility(View view, int visibility) {
        if (view == null) {
            ToastUtil.debugToast(mContext, "You must keep the view not null", false);
            return;
        }
        view.setVisibility(visibility);
    }

    public boolean hasPopupHint() {
        return false;
    }

    protected boolean isPopupHintPrepared;

    public boolean isPopupHintPrepared() {
        return isPopupHintPrepared;
    }

    public void showPopupHint() {}

    public void hidePopupHint() {}

}
